using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using MIMPGameLibrary;
using MIMPWinForms.MIMPGameServices;
using MIMPWinForms.XnaControls;

namespace MIMPWinForms.Forms
{
    public partial class MainForm : Form, IControlPanelEventsService
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        #region IControlPanelEventsService events and raisers
        /// <summary>
        /// Occurs when the user clicks the Add New Monster button.
        /// EventData is the Monster the user wishes to add.
        /// </summary>
        public event EventHandler<EventArgs<Monster>> AddNewMonsterButtonClicked;
        /// <summary>
        /// Occurs when the user clicks the Attack button.
        /// </summary>
        public event EventHandler AttackButtonClicked;
        /// <summary>
        /// Occurs when the user clicks the Move button.
        /// </summary>
        public event EventHandler MoveButtonClicked;
        /// <summary>
        /// Occurs when the user clicks the Second Move button.
        /// </summary>
        public event EventHandler SecondMoveButtonClicked;
        /// <summary>
        /// Occurs when the user clicks the End Turn button.
        /// </summary>
        public event EventHandler EndTurnButtonClicked;
        /// <summary>
        /// Occurs when the user clicks the Swoop Attack button.
        /// </summary>
        public event EventHandler SwoopAttackButtonClicked;
        /// <summary>
        /// Occurs when the user clicks the Dive button.
        /// </summary>
        public event EventHandler DiveButtonClicked;
        /// <summary>
        /// Occurs when the user clicks a spell casting button. EventData is the type of Spell associated with the clicked button.
        /// </summary>
        public event EventHandler<EventArgs<Monster.Spells>> SpellButtonClicked;
        /// <summary>
        /// Occurs when the user presses Enter while the ChatEntry text box has focus. EventData is the text in the text box at that time.
        /// </summary>
        public event EventHandler<EventArgs<string>> ChatTextEntered;
        /// <summary>
        /// Occurs when the user wants to cancel whatever action is pending.
        /// </summary>
        public event EventHandler CancelButtonClicked;
        /// <summary>
        /// Occurs when the user clicks the Delete Monster button.
        /// </summary>
        public event EventHandler DeleteMonsterButtonClicked;
        /// <summary>
        /// Occurs when the user clicks the Done button, indicating that they are done selecting attackers/defenders.
        /// </summary>
        public event EventHandler DoneButtonClicked;
        /// <summary>
        /// Occurs when the user is done assigning damage to the losing monsters in an attack.
        /// </summary>
        public event EventHandler<EventArgs<Dictionary<Monster, int>>> DamageAssigned;

        protected void RaiseAddNewMonsterButtonClicked(Monster toAdd) {
            if (AddNewMonsterButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising AddNewMonsterButtonClicked");
                AddNewMonsterButtonClicked(this, new EventArgs<Monster>(toAdd));
            }
        }

        protected void RaiseAttackButtonClicked() {
            if (AttackButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising AttackButtonClicked");
                AttackButtonClicked(this, EventArgs.Empty);
            }
        }

        protected void RaiseMoveButtonClicked() {
            if (MoveButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising MoveButtonClicked");
                MoveButtonClicked(this, EventArgs.Empty);
            }
        }

        protected void RaiseSecondMoveButtonClicked() {
            if (SecondMoveButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising SecondMoveButtonClicked");
                SecondMoveButtonClicked(this, EventArgs.Empty);
            }
        }

        protected void RaiseEndTurnButtonClicked() {
            if (EndTurnButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising EndTurnButtonClicked");
                EndTurnButtonClicked(this, EventArgs.Empty);
            }
        }

        protected void RaiseSwoopAttackButtonClicked() {
            if (SwoopAttackButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising SwoopAttackButtonClicked");
                SwoopAttackButtonClicked(this, EventArgs.Empty);
            }
        }

        protected void RaiseDiveButtonClicked() {
            if (DiveButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising DiveButtonClicked");
                DiveButtonClicked(this, EventArgs.Empty);
            }
        }

        protected void RaiseSpellButtonClicked(Monster.Spells spell) {
            if (SpellButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising SpellButtonClicked with " + Enum.GetName(typeof(Monster.Spells), spell));
                SpellButtonClicked(this, new EventArgs<Monster.Spells>(spell));
            }
        }

        protected void RaiseChatTextEntered(string message) {
            if (ChatTextEntered != null) {
                if (log.IsInfoEnabled) log.Info("Raising ChatTextEntered with " + message);
                ChatTextEntered(this, new EventArgs<string>(message));
            }
        }

        protected void RaiseCancelButtonClicked() {
            if (CancelButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising CancelButtonClicked");
                CancelButtonClicked(this, EventArgs.Empty);
            }
        }

        protected void RaiseDeleteMonsterButtonClicked() {
            if (DeleteMonsterButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising DeleteMonsterButtonClicked");
                DeleteMonsterButtonClicked(this, EventArgs.Empty);
            }
        }

        protected void RaiseDoneButtonClicked() {
            if (DoneButtonClicked != null) {
                if (log.IsInfoEnabled) log.Info("Raising DoneButtonClicked");
                DoneButtonClicked(this, EventArgs.Empty);
            }
        }

        protected void RaiseDamageAssigned(Dictionary<Monster, int> assignment) {
            if (DamageAssigned != null) {
                if (log.IsInfoEnabled) log.Info("Raising DamageAssigned");
                DamageAssigned(this, new EventArgs<Dictionary<Monster, int>>(assignment));
            }
        }

        #endregion

        public const string INSTRUCTIONS_SETUP = "Use the drop down and text box to the left to select a monster type and name, then click Deploy New Monster to add it.";
        public const string INSTRUCTIONS_DEPLOYMENT = "Click a hex to deploy your new monster there, or click Cancel.";
        public const string INSTRUCTIONS_DELETE = "Click the monster you want to remove, or click Cancel.";
        public const string INSTRUCTIONS_PLAY = "Click on a mosnter you control to select it. Right click and hold on any monster or hex to get info.";
        public const string INSTRUCTIONS_SELECTED = "Use the buttons to the left to move, attack, or take another action with the selected monster.";
        public const string INSTRUCTIONS_MOVE = "Click on a hex to move the selected monster there.";
        public const string INSTRUCTIONS_ATTACK = "Click a monster to target it with your attack. After choosing your target you will have a chance to select additional attackers.";
        public const string INSTRUCTIONS_ADD_ATTACKERS = "Click a monster to have it assist the attack; ctrl-click to stop assisting. Click Done when ready.";
        public const string INSTRUCTIONS_DEFEND = "Click a monster to have it assist in defense; ctrl-click to stop assisting. Click Done when ready.";
        public const string INSTRUCTIONS_DIVE = "Click any Water hex to resurface in.";
        public const string INSTRUCTIONS_SPELL = "Click a hex to target it with your spell.";

        /// <summary>
        /// Occurs when the user clicks the "Main Menu" button on the control panel.
        /// </summary>
        public event EventHandler MainMenuButtonClicked;

        protected virtual void RaiseMainMenuButtonClicked() {
            if (MainMenuButtonClicked != null) {
                MainMenuButtonClicked(this, EventArgs.Empty);
            }
        }

        private int monsterCount = 1;

        IGameStateEventsService gameStateEvents;
        ChatModeSelector chatMode;

        public MIMPGameScreenControl GameScreen {
            get { return mimpGameScreenControl; }
        }

        public MainForm() {
            if (log.IsInfoEnabled) log.Info("Entered MainForm constructor");
            InitializeComponent();

            PopulateCmbMonsterToAdd();

            common_txtInstructions.Text = INSTRUCTIONS_SETUP;
            setup_txtChatEntry.KeyPress += new KeyPressEventHandler(setup_txtChatEntry_KeyPress);

            common_btnScrollUp.MouseDown += new MouseEventHandler(ScrollButton_MouseDown);
            common_btnScrollDown.MouseDown += new MouseEventHandler(ScrollButton_MouseDown);
            common_btnScrollLeft.MouseDown +=new MouseEventHandler(ScrollButton_MouseDown);
            common_btnScrollRight.MouseDown +=new MouseEventHandler(ScrollButton_MouseDown);
            common_btnScrollUp.MouseUp += new MouseEventHandler(ScrollButton_MouseUp);
            common_btnScrollDown.MouseUp += new MouseEventHandler(ScrollButton_MouseUp);
            common_btnScrollLeft.MouseUp +=new MouseEventHandler(ScrollButton_MouseUp);
            common_btnScrollRight.MouseUp +=new MouseEventHandler(ScrollButton_MouseUp);

            common_tooltip.SetToolTip(common_btnEndTurn, "End Your Turn");
            common_tooltip.SetToolTip(common_btnMainMenu, "Main Menu");
            common_tooltip.SetToolTip(common_btnCancel, "Cancel pending action");

            this.Resize += new EventHandler(MainForm_Resize);

            playControlPanel.Location = setupControlPanel.Location;
            playControlPanel.Anchor = setupControlPanel.Anchor;

            this.WindowState = FormWindowState.Maximized;
            if (log.IsInfoEnabled) log.Info("Exiting MainForm constructor");
        }

        void ScrollButton_MouseDown(object sender, MouseEventArgs e) {
            if (log.IsInfoEnabled) log.Info("Entered ScrollButton_MouseDown");
            sender = (Button)sender;
            if (log.IsDebugEnabled) log.Debug("sender: " + sender);

            if (sender.Equals(common_btnScrollUp)) {
                mimpGameScreenControl.StartScrolling(MIMPGameScreenControl.ScrollDirections.Up);
            } else if (sender.Equals(common_btnScrollDown)) {
                mimpGameScreenControl.StartScrolling(MIMPGameScreenControl.ScrollDirections.Down);
            } else if (sender.Equals(common_btnScrollLeft)) {
                mimpGameScreenControl.StartScrolling(MIMPGameScreenControl.ScrollDirections.Left);
            } else if (sender.Equals(common_btnScrollRight)) {
                mimpGameScreenControl.StartScrolling(MIMPGameScreenControl.ScrollDirections.Right);
            }

            if (log.IsInfoEnabled) log.Info("Exiting ScrollButton_MouseDown");
        }

        void ScrollButton_MouseUp(object sender, MouseEventArgs e) {
            mimpGameScreenControl.StopScrolling();
        }

        void MainForm_Resize(object sender, EventArgs e) {
            if (log.IsInfoEnabled) log.Info("Entered MainForm_Resize");
            //the game screen control does not support autosize or anchoring, so we must adjust its size ourselves
            int height = this.Height - setupControlPanel.Location.Y;
            mimpGameScreenControl.Width = this.Width;
            mimpGameScreenControl.Height = this.Height - height;

            //the "Anchor" property takes care of some of the resizing of the scroll buttons, 
            //but it doesn't do a perfect job, so we manually adjust them a bit.
            common_btnScrollDown.Location = new Point(common_btnScrollDown.Location.X, mimpGameScreenControl.Height - common_btnScrollDown.Height);
            common_btnScrollLeft.Height = mimpGameScreenControl.Height - common_btnScrollDown.Height - common_btnScrollUp.Height; ;
            common_btnScrollRight.Height = mimpGameScreenControl.Height - common_btnScrollDown.Height - common_btnScrollUp.Height;
            if (log.IsInfoEnabled) log.Info("Exiting MainForm_Resize");
        }

        public void SetServices(ServiceProvider gameServices) {
            if (log.IsInfoEnabled) log.Info("Entered SetServices");
            //get Services implementers           
            gameStateEvents = (IGameStateEventsService)(gameServices.GetService(typeof(IGameStateEventsService)));
            gameStateEvents.ChatYellSent += new EventHandler<EventArgs<Player, string>>(gameStateEvents_ChatYellSent);
            gameStateEvents.ApplicationMessageSent += new EventHandler<EventArgs<string>>(gameStateEvents_ApplicationMessageSent);
            gameStateEvents.ActivePlayerChanged += new EventHandler<EventArgs<Player>>(gameStateEvents_ActivePlayerChanged);
            gameStateEvents.NewTurnBegan += new EventHandler<EventArgs<Player>>(gameStateEvents_NewTurnBegan);
            gameStateEvents.PlayersDeploymentPointsChanged += new EventHandler<EventArgs<Player>>(gameStateEvents_PlayersDeploymentPointsChanged);
            gameStateEvents.MonsterAdded += new EventHandler<EventArgs<Monster>>(gameStateEvents_MonsterAdded);
            gameStateEvents.ActionFailed += new EventHandler<EventArgs<string>>(gameStateEvents_ActionFailed);
            gameStateEvents.MonsterRemoved += new EventHandler<EventArgs<Monster>>(gameStateEvents_MonsterRemoved);
            gameStateEvents.GamePhaseChanged += new EventHandler<EventArgs<GameState.Phases>>(gameStateEvents_GamePhaseChanged);
            gameStateEvents.SelectedMonsterChanged += new EventHandler<EventArgs<Monster>>(gameStateEvents_SelectedMonsterChanged);
            gameStateEvents.MonsterMoved += new EventHandler<EventArgs<Monster>>(gameStateEvents_MonsterMoved);
            gameStateEvents.MonsterTookSecondMove += new EventHandler<EventArgs<Monster>>(gameStateEvents_MonsterTookSecondMove);
            gameStateEvents.AttackResultCalculated += new EventHandler<EventArgs<AttackResult>>(gameStateEvents_AttackResultCalculated);
            gameStateEvents.AttackTargetChosen += new EventHandler<EventArgs<Monster>>(gameStateEvents_AttackTargetChosen);
            gameStateEvents.AttackersFinalized += new EventHandler<EventArgs<List<Monster>, Monster>>(gameStateEvents_AttackersFinalized);
            gameStateEvents.AttackCompleted += new EventHandler<EventArgs<List<Monster>>>(gameStateEvents_AttackCompleted);
        }

        void gameStateEvents_AttackCompleted(object sender, EventArgs<List<Monster>> e) {
            if (log.IsInfoEnabled) log.Info("Entered gameStateEvents_AttackCompleted");
            StringBuilder msg = new StringBuilder();
            foreach (Monster m in e.EventData) {
                msg.Append(m).Append(" now has " + m.Health + " health remaining.");
                if (m != e.EventData[e.EventData.Count -1]) {
                    msg.Append("\n");
                }
            }
            PrintApplicationMessage(msg.ToString());

            play_ButtonsFlowLayout.Enabled = true;
            play_btnDone.Visible = false;
            common_btnCancel.Enabled = true;
            common_btnEndTurn.Enabled = true;
            common_txtInstructions.Text = INSTRUCTIONS_PLAY;
            mimpGameScreenControl.Cursor = Cursors.Default;
            if (log.IsInfoEnabled) log.Info("Exiting gameStateEvents_AttackCompleted");
        }

        void gameStateEvents_AttackersFinalized(object sender, EventArgs<List<Monster>, Monster> e) {
            if (log.IsInfoEnabled) log.Info("Entered gameStateEvents_AttackersFinalized");
            StringBuilder msg = new StringBuilder();
            msg.Append(e.PrimaryEventData[0].Controller + " is attacking " + e.SecondaryEventData + " with: ");
            foreach (Monster m in e.PrimaryEventData) {
                msg.Append(m);
                if (m != e.PrimaryEventData[e.PrimaryEventData.Count -1]) {
                    msg.Append(", ");
                }
            }
            PrintApplicationMessage(msg.ToString());

            common_txtInstructions.Text = INSTRUCTIONS_DEFEND;
            if (log.IsInfoEnabled) log.Info("Exiting gameStateEvents_AttackersFinalized");
        }



        void gameStateEvents_NewTurnBegan(object sender, EventArgs<Player> e) {
            if (log.IsInfoEnabled) log.Info("Entered gameStateEvents_NewTurnBegan");
            setup_rchtxtMessageLog.SelectionColor = Color.Black;
            setup_rchtxtMessageLog.SelectionFont = new Font(setup_rchtxtMessageLog.SelectionFont, FontStyle.Bold);
            setup_rchtxtMessageLog.SelectedText = "It is now " + e.EventData.ToString() + "'s turn.\n";
            setup_rchtxtMessageLog.ScrollToCaret();

            setup_txtActivePlayerName.Text = e.EventData.Name;
            setup_txtActivePlayerColor.BackColor = Constants.XnaColorToSysColor(e.EventData.Color);
            if (log.IsInfoEnabled) log.Info("Exiting gameStateEvents_NewTurnBegan");
        }

        void gameStateEvents_AttackTargetChosen(object sender, EventArgs<Monster> e) {
            if (log.IsInfoEnabled) log.Info("Entered gameStateEvents_AttackTargetChosen");
            if (log.IsDebugEnabled) log.Debug("Target is: " + e.EventData);
            common_txtInstructions.Text = INSTRUCTIONS_ADD_ATTACKERS;
            mimpGameScreenControl.Cursor = Cursors.Hand;
            play_btnDone.Visible = play_btnDone.Enabled = true;
            if (log.IsInfoEnabled) log.Info("Exiting gameStateEvents_AttackTargetChosen");
        }

        void gameStateEvents_AttackResultCalculated(object sender, EventArgs<AttackResult> e) {
            if (log.IsInfoEnabled) log.Info("Entered gameStateEvents_AttackResultCalculated");
            if (log.IsDebugEnabled) log.Debug("Building result message box");

            StringBuilder resultText = new StringBuilder();
            foreach (KeyValuePair<Monster, int> kvp in e.EventData.DamageDoneByMonsters) {
                string partial = "[" + kvp.Key.Controller + "] " + kvp.Key + " rolled: ";
                partial = partial.PadRight(40, '.');
                resultText.Append(partial).Append(kvp.Value).Append("\n");
            }
            string title = "";

            if (e.EventData.TotalDamageDone == 0) {
                title = "The combat was a draw!";
                MessageBox.Show(resultText.ToString(), title, MessageBoxButtons.OK, MessageBoxIcon.None);
            } else {
                title = e.EventData.DidAttackersWin ? "Attacking team won!" : "Defending team won!";
                resultText.Append(e.EventData.TotalDamageDone + " damage will be dealt.");

                MessageBox.Show(resultText.ToString(), title, MessageBoxButtons.OK, MessageBoxIcon.None);

                DamageAssignmentBox box = new DamageAssignmentBox(e.EventData);
                box.Closed += new EventHandler(box_Closed);
                box.ShowDialog();
            }

            PrintApplicationMessage(title);
        }

        void box_Closed(object sender, EventArgs e) {
            RaiseDamageAssigned(((DamageAssignmentBox)sender).Assignments);
        }

        void gameStateEvents_ActionFailed(object sender, EventArgs<string> e) {
            if (log.IsInfoEnabled) log.Info("Entered gameStateEvents_ActionFailed");
            MessageBox.Show(e.EventData, "Action failed", MessageBoxButtons.OK, MessageBoxIcon.None);
            mimpGameScreenControl.Cursor = Cursors.Default;

            common_btnCancel.Enabled = false;
            
            if (setupControlPanel.Visible) {
                common_txtInstructions.Text = INSTRUCTIONS_SETUP;
                setup_btnAddMonster.Enabled = true;
            } else {
                play_ButtonsFlowLayout.Enabled = true;
                common_txtInstructions.Text = INSTRUCTIONS_PLAY;
            }

            
            if (log.IsInfoEnabled) log.Info("Exiting gameStateEvents_ActionFailed");
        }

        void gameStateEvents_ActivePlayerChanged(object sender, EventArgs<Player> e) {
            MessageBox.Show(e.EventData + " now has control of the game.", "Active Player: " + e.EventData, MessageBoxButtons.OK, MessageBoxIcon.None);
        }

        void gameStateEvents_GamePhaseChanged(object sender, EventArgs<GameState.Phases> e) {
            setupControlPanel.Visible = e.EventData == GameState.Phases.Setup;
            playControlPanel.Visible = e.EventData == GameState.Phases.Play;
        }

        void gameStateEvents_ApplicationMessageSent(object sender, EventArgs<string> e) {
            PrintApplicationMessage(e.EventData);
        }

        /// <summary>
        /// Writes the system message to the message log text box.
        /// </summary>
        private void PrintApplicationMessage(string message) {
            setup_rchtxtMessageLog.SelectionFont = new Font(setup_rchtxtMessageLog.SelectionFont, FontStyle.Regular);
            setup_rchtxtMessageLog.SelectionColor = Color.Gray;
            setup_rchtxtMessageLog.SelectedText = message + '\n';
            setup_rchtxtMessageLog.ScrollToCaret();
        }

        /// <summary>
        /// Writes a message to the message log with the name of the player who sent the chat, followed by the
        /// chat text sent.
        /// </summary>
        void gameStateEvents_ChatYellSent(object sender, EventArgs<Player, string> e) {
            setup_rchtxtMessageLog.SelectionColor = Constants.XnaColorToSysColor(e.PrimaryEventData.Color);
            setup_rchtxtMessageLog.SelectionFont = new Font(setup_rchtxtMessageLog.SelectionFont, FontStyle.Bold);
            setup_rchtxtMessageLog.SelectedText = e.PrimaryEventData.Name + ":";

            setup_rchtxtMessageLog.SelectionColor = Color.Black;
            setup_rchtxtMessageLog.SelectionFont = new Font(setup_rchtxtMessageLog.SelectionFont, FontStyle.Regular);
            setup_rchtxtMessageLog.SelectedText = e.SecondaryEventData + '\n';
            setup_rchtxtMessageLog.ScrollToCaret();
        }

        /// <summary>
        /// Checks to see if the key pressed was Enter. If so, raises a ChatTextEntered event and clears
        /// the chat entry text box.
        /// </summary>
        void setup_txtChatEntry_KeyPress(object sender, KeyPressEventArgs e) {
            if (e.KeyChar == '\r') {
                e.Handled = true;

                //If no there is no text, do not do anything.
                if (String.IsNullOrEmpty(setup_txtChatEntry.Text)) {
                    return;
                }

                RaiseChatTextEntered(setup_txtChatEntry.Text);

                setup_txtChatEntry.Clear();
            }
        }

        private void setup_btnChatMode_Click(object sender, EventArgs e) {
            if (chatMode == null) {
                chatMode = new ChatModeSelector(gameStateEvents.Players);
            }
            chatMode.Show();
        }

        private void common_btnEndTurn_Click(object sender, EventArgs e) {
            string confirmMsg = "";
            string title = "";
            if (setupControlPanel.Visible) {
                title = "Confirm Setup Done";
                if (int.Parse(setup_txtDeploymentPointsRemaining.Text) > 0) {
                    confirmMsg = "You have " + setup_txtDeploymentPointsRemaining.Text +
                    " deployment points remaining.\nAre you sure you want to end your setup phase?";
                } else {
                    confirmMsg = "Are you sure you want to end your setup phase?";
                }

            } else {
                title = "Confirm Turn End";
                confirmMsg = "Are you sure you want to end your turn?";
            }
            if (MessageBox.Show(confirmMsg, title, MessageBoxButtons.OKCancel,
                MessageBoxIcon.Question) == DialogResult.OK) {
                RaiseEndTurnButtonClicked();
            }
        }

        private void common_btnMainMenu_Click(object sender, EventArgs e) {
            RaiseMainMenuButtonClicked();
        }



        #region Setup Phase controls and methods
        void gameStateEvents_MonsterRemoved(object sender, EventArgs<Monster> e) {
            PrintApplicationMessage(e.EventData.Controller + " removed " + e.EventData + ".");
            common_btnCancel.Enabled = false;
            setup_btnAddMonster.Enabled = true;
            setup_btnDelete.Enabled = mimpGameScreenControl.MonsterDisplayCount > 1;
            common_txtInstructions.Text = INSTRUCTIONS_SETUP;
            mimpGameScreenControl.Cursor = Cursors.Default;
        }

        void gameStateEvents_MonsterAdded(object sender, EventArgs<Monster> e) {
            PrintApplicationMessage(e.EventData.Controller.Name + " deployed " + e.EventData.ToString() +
                " to " + e.EventData.Location.ToString() + ", for a cost of " +
                +e.EventData.Cost + " deployment points.");
            common_btnCancel.Enabled = false;
            setup_btnAddMonster.Enabled = true;
            setup_btnDelete.Enabled = true;
            common_txtInstructions.Text = INSTRUCTIONS_SETUP;
            monsterCount++;
            setup_txtMonsterName.Text = "Monster " + monsterCount;
            mimpGameScreenControl.Cursor = Cursors.Default;
        }

        void gameStateEvents_PlayersDeploymentPointsChanged(object sender, EventArgs<Player> e) {
            setup_txtDeploymentPointsRemaining.Text = "" + e.EventData.DeploymentPoints;
        }

        /// <summary>
        /// Populates the cmbMonsterToAdd combo box with a list of all the Monsters 
        /// that Players can add to this game.
        /// </summary>
        private void PopulateCmbMonsterToAdd() {
            List<Monster> monstersFromXML = Monster.CreateMonstersFromXMLs(Constants.MONSTER_XML_DIRECTORY);
            foreach (Monster m in monstersFromXML) {
                cmbMonsterToAdd.Items.Add(m);
            }
            setup_lblMonsterToAddInfo.Text = "";
        }

        private void cmbMonsterToAdd_SelectedIndexChanged(object sender, EventArgs e) {
            Monster selected = (Monster)(cmbMonsterToAdd.SelectedItem);
            setup_lblMonsterToAddInfo.Text = selected.GetMonsterInfoString(GameState.Phases.Setup);
            setup_btnAddMonster.Enabled = true;
            setup_btnDetailedInfo.Enabled = true;
            setup_sptvwrViewingMonster.SpriteContentName = Constants.MONSTER_ICON_DIRECTORY + selected.IconName;
        }

        private void setup_btnAddMonster_Click(object sender, EventArgs e) {
            Monster copy = ((Monster)(cmbMonsterToAdd.SelectedItem)).ShallowCopy();
            copy.Name = setup_txtMonsterName.Text;
            common_txtInstructions.Text = INSTRUCTIONS_DEPLOYMENT;
            common_btnCancel.Enabled = true;
            setup_btnAddMonster.Enabled = false;
            mimpGameScreenControl.Cursor = Cursors.Hand;
            RaiseAddNewMonsterButtonClicked(copy);
        }

        private void common_btnCancel_Click(object sender, EventArgs e) {
            RaiseCancelButtonClicked();
        }

        private void setup_btnDelete_Click(object sender, EventArgs e) {
            setup_btnDelete.Enabled = false;
            common_btnCancel.Enabled = true;
            common_txtInstructions.Text = INSTRUCTIONS_DELETE;
            mimpGameScreenControl.Cursor = Cursors.Cross;
            RaiseDeleteMonsterButtonClicked();
        }


        #endregion



        private void setup_btnDetailedInfo_Click(object sender, EventArgs e) {

        }

        #region Play Phase controls and methods

        void gameStateEvents_SelectedMonsterChanged(object sender, EventArgs<Monster> e) {
            if (log.IsInfoEnabled) log.Info("Entered gameStateEvents_SelectedMonstersChanged");
            if (e.EventData != null) {
                play_ButtonsFlowLayout.Enabled = true;
                Monster selected = e.EventData;
                if (log.IsDebugEnabled) log.Debug("selected monster is: " + selected);
                try {
                    play_sptvwrViewingMonster.SpriteContentName = Constants.MONSTER_ICON_DIRECTORY + selected.IconName;
                } catch (Exception ex) {
                    if (log.IsErrorEnabled) log.Error("Error loading monster image file: " + Constants.MONSTER_ICON_DIRECTORY + selected.IconName, ex);
                }
                play_lblSelectedMonsterInfo.Text = selected.GetMonsterInfoString(GameState.Phases.Play);
                play_btnMove.Enabled = selected.MovesRemaining > 0;
                play_btnAttack.Enabled = selected.ActionsRemaining > 0;
                play_btnSecondMove.Enabled = selected.ActionsRemaining > 0;
                play_btnSwoop.Visible = (selected.Abilities & Monster.SpecialAbilities.Flight) != 0;
                play_btnSwoop.Enabled = selected.ActionsRemaining > 0;
                play_btnDive.Visible = (selected.Abilities & Monster.SpecialAbilities.Diving) != 0;
                play_btnDive.Enabled = selected.ActionsRemaining > 0;
                play_btnCastSpell.Visible = (selected.Abilities & (Monster.SpecialAbilities.Enchantment | Monster.SpecialAbilities.Sorcery)) != 0;
                play_btnCastSpell.Enabled = selected.ActionsRemaining > 0;
                common_txtInstructions.Text = INSTRUCTIONS_SELECTED;
            } else {
                play_ButtonsFlowLayout.Enabled = false;
                common_txtInstructions.Text = INSTRUCTIONS_PLAY;
            }
            if (log.IsInfoEnabled) log.Info("Exiting gameStateEvents_SelectedMonstersChanged");
        }


        void gameStateEvents_MonsterMoved(object sender, EventArgs<Monster> e) {
            play_lblSelectedMonsterInfo.Text = e.EventData.GetMonsterInfoString(GameState.Phases.Play);
            mimpGameScreenControl.Cursor = Cursors.Default;
            PrintApplicationMessage(e.EventData.Controller + " moved " + e.EventData + " to " + e.EventData.Location);
        }

        private void play_btnAttack_Click(object sender, EventArgs e) {
            common_txtInstructions.Text = INSTRUCTIONS_ATTACK;
            mimpGameScreenControl.Cursor = Cursors.Cross;
            play_ButtonsFlowLayout.Enabled = false;
            common_btnCancel.Enabled = true;
            RaiseAttackButtonClicked();
        }

        private void play_btnMove_Click(object sender, EventArgs e) {
            common_txtInstructions.Text = INSTRUCTIONS_MOVE;
            mimpGameScreenControl.Cursor = Cursors.Hand;
            play_ButtonsFlowLayout.Enabled = false;
            common_btnCancel.Enabled = true;
            RaiseMoveButtonClicked();
        }

        private void play_btnSecondMove_Click(object sender, EventArgs e) {
            if (MessageBox.Show("Taking a second move will grant the selected monster movement points equal to half its speed,\nfor the cost of one action point. Are you sure you want to do this?",
                "Confirm Second Move", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK) {
                if (log.IsDebugEnabled) log.Debug("User confirmed intent to take second move.");
                RaiseSecondMoveButtonClicked();
            }
        }

        void gameStateEvents_MonsterTookSecondMove(object sender, EventArgs<Monster> e) {
            play_lblSelectedMonsterInfo.Text = e.EventData.GetMonsterInfoString(GameState.Phases.Play);
            PrintApplicationMessage(e.EventData + " used one action point to get a second move.");
        }

        #endregion

        private void play_btnDone_Click(object sender, EventArgs e) {
            RaiseDoneButtonClicked();
        }
    }
}